#pragma once
#include<iostream>
#include<functional>
#include<sys/epoll.h>
#include"../Log/log.hpp"
#include<vector>
#include<unordered_map>
#include<cstring>
#include<cassert>
#include<thread>
#include<sys/eventfd.h>
#include<mutex>
#include<sys/timerfd.h>
#include<unistd.h>

#define MAX_EVENT_NUM 100
#define DEFAULT_TIMEWHEEL_SIZE 60

class Poller;
class EventLoop;
class Channel{
private:
    int _fd;
    uint32_t _event;//当前需要监控的事件
    uint32_t _revent;//当前连接触发的事件
    EventLoop* _loop;

    using EventCallback = std::function<void()>;
    EventCallback _read_callback;//可读事件被触发的回调函数
    EventCallback _write_callback;//可写事件被触发的回调函数
    EventCallback _error_callback;//错误事件被触发的回调函数
    EventCallback _close_callback;//连接断开事件被触发的回调函数
    EventCallback _event_callback;//任意事件被触发的回调函数

public:
    Channel(int fd, EventLoop* loop)
    :_fd(fd)
    ,_event(0)
    ,_revent(0)
    ,_loop(loop)
    {}

    int get_fd()
    {
        return _fd;
    }

    //获取要监控的事件_event
    uint32_t get_event()
    {
        return _event;
    }

    //设置连接触发事件
    void set_revent(uint32_t event)
    {
        _revent = event;
    }

    //设置读事件回调
    void set_read_callback(const EventCallback &cb)
    {
        _read_callback = cb;
    }
    //设置写事件回调
    void set_write_callback(const EventCallback &cb)
    {
        _write_callback = cb;
    }
    //设置错误事件回调
    void set_error_callback(const EventCallback &cb)
    {
        _error_callback = cb;
    }
    //设置连接断开事件回调
    void set_close_callback(const EventCallback &cb)
    {
        _close_callback = cb;
    }
    //设置任意事件回调
    void set_event_callback(const EventCallback &cb)
    {
        _event_callback = cb;
    }

    //是否监控了可读
    bool Readable()
    {
        return _event & EPOLLIN;
    }
    //是否监控了可写
    bool Writeable()
    {
        return _event & EPOLLOUT;
    }
    
    //启动读事件监控
    void EnableRead()
    {
        _event |= EPOLLIN;
        UpdateAll();
    }
    //启动写事件监控
    void EnableWrite()
    {
        _event |= EPOLLOUT;
        // std::cout << _event << std::endl;
        UpdateAll();
    }
    //关闭读事件监控
    void DisableRead()
    {
        _event &= ~EPOLLIN;
        UpdateAll();
    }
    //关闭写事件监控
    void DisableWrite()
    {
        _event &= ~EPOLLOUT;
        UpdateAll();

    }
    //关闭所有事件监控
    void DisableALL()
    {
        _event = 0;
        UpdateAll();
    }
    //移除所有监控，在定义EventLoop后定义
    void RemoveAll();

    //更新监控事件,在定义EventLoop后定义
    void UpdateAll();

    EventLoop* GetLoop()
    {
        return _loop;
    }
    //事件处理
    void HandleEvent()
    {
        if((_revent & EPOLLIN) || (_revent & EPOLLRDHUP) || (_revent & EPOLLPRI))
        {
            //任意事件处理要在读事件之后，因为如果读事件处理时间久，fd直接断开，就会出错。
            //因此要在读事件结束后，刷新fd的活跃度
            if(_read_callback) _read_callback();
            if(_event_callback) _event_callback();
        }

        if(_revent & EPOLLOUT)
        {
            if(_write_callback) _write_callback();    
            if(_event_callback) _event_callback();
        }
        else if(_revent & EPOLLERR)
        {
            //调用错误回调后，fd会被释放。所以要在释放前调用任意事件回调函数
            if(_event_callback) _event_callback();
            if(_error_callback) _error_callback();
        }
        else if(_revent & EPOLLHUP)
        {
            if(_event_callback) _event_callback();
            if(_close_callback) _close_callback();
        }
    }
};


class Poller{
private:
    int _epfd;//epoll的文件描述符
    struct epoll_event _ready_event[MAX_EVENT_NUM];//有就绪事件数组
    std::unordered_map<int, Channel*> _map;//要监控的文件描述符的hash表

    //文件描述符是否被监控
    bool has_channel(Channel* channel)
    {
        auto it = _map.find(channel->get_fd());
        if(it == _map.end())
        {
            return false;
        }
        return true;
    }

    //epoll基本操作封装
    void epoll_op(Channel* channel, int op)
    {
        int fd = channel->get_fd();
        struct epoll_event event;
        event.events = channel->get_event();
        
        event.data.fd = fd;
        int ret = epoll_ctl(_epfd, op, channel->get_fd(), &event);
        if (ret < 0) {
            ERR_LOG("epollctl fail!");
        }
   }
public:
    Poller()
    {
        _epfd = epoll_create(1);
        if(_epfd < 0)
        {
            ERR_LOG("epoll create fail");
            return;
        }
    }
    //更新描述符事件,无则添加有则修改
    void Update(Channel* channel)
    {   
        if(has_channel(channel))
        {
            //存在描述符,修改
            epoll_op(channel, EPOLL_CTL_MOD);
        }
        else
        {
            //不存在描述符，添加
            INF_LOG("Adding new channel: fd=%d", channel->get_fd());
            epoll_op(channel, EPOLL_CTL_ADD);
            _map.insert(std::make_pair(channel->get_fd(), channel));
        }
    }

    //移除监控
    void Remove(Channel* channel)
    {
        //存在才删除
        if(has_channel(channel))
        {
           _map.erase(channel->get_fd());
            epoll_op(channel, EPOLL_CTL_DEL);
        }
    }

    //开始监控，获取就绪的Channel
    void Handle(std::vector<Channel*>* ready) 
    {
        int num = epoll_wait(_epfd, _ready_event, MAX_EVENT_NUM, -1);
        if(num < 0)
        {
            if(errno == EINTR)//阻塞时被信号打断
            {
                DBG_LOG("epoll_wait interrupted by signal");
                return;
            }
            else
            {
                ERR_LOG("epoll wait fail:%s", strerror(errno));
                return;
            }
        }

        for(int i = 0; i < num; i++)
        {
            auto it = _map.find(_ready_event[i].data.fd);
            assert(it != _map.end());
            it->second->set_revent(_ready_event[i].events);
            ready->push_back(it->second);
        }
    }
};

using task_cb = std::function<void()>;
using del_timer = std::function<void()>;
class TimerTask//对需要定时的事件的封装
{
private:
    long unsigned int _id;//事件id
    unsigned int _timeout;//超时时间
    task_cb _cb;//删除任务的回调函数
    del_timer _delTimer;//删除任务结构体的回调函数，因为任务结构体保存在TimeWhell中，需要在其中定义函数
    bool _canceled;
public:
    TimerTask(long unsigned int id, unsigned int timeout, task_cb cb)
    :_id(id),
    _timeout(timeout),
    _cb(cb),
    _canceled(false)
    {}

    ~TimerTask()
    {
        if (_canceled == false) _cb();
        _delTimer();
    }

    void Cancel() 
    { 
        _canceled = true; 
    }

    void set_delTimer(del_timer cb)
    {
        _delTimer = cb;
    }

    unsigned int get_timeout()
    {
        return _timeout;
    }
};
class TimeWheel//时间轮定时器，对封装后的事件进行组织
{
private:
    int _capacity;//时间轮大小,最大延迟时间
    int _tick;//时间指针所在的位置，每一个单位时间就移动一位。
    std::vector<std::vector<std::shared_ptr<TimerTask>>> _wheel;//时间轮
    std::unordered_map<long unsigned int, std::weak_ptr<TimerTask>> _timers;//用来查找有哪些事件进入时间轮，是对共享指针的观测，要用weak指针

    int _timer_fd;//超时事件的描述符
    EventLoop* _loop;//对timerfd的事件进行监控
    std::unique_ptr<Channel> _channel;//对timerfd进行事件管理，设置回调

    static int InitTimerfd()
    {
        int fd = timerfd_create(CLOCK_MONOTONIC, 0);
        if(fd < 0)
        {
            ERR_LOG("timerfd create fail");
            abort();
        }

        struct itimerspec itime;
        itime.it_value.tv_nsec = 0;
        itime.it_value.tv_sec = 1;//开始1s后定时器触发
        itime.it_interval.tv_nsec = 0;
        itime.it_interval.tv_sec = 1;//第一次触发后，每隔1s触发一次
        int ret = timerfd_settime(fd, 0, &itime, nullptr);
        if(ret < 0)
        {
            ERR_LOG("timetfd settime fail")
            abort();
        }
        return fd;
    }

    //读定时器描述符，将描述符内容清空，否则会一直发信号
    int ReadTimerfd()
    {
        uint64_t val;
        int ret = read(_timer_fd, &val, sizeof(val));
        if(ret < 0)
        {
            ERR_LOG("read timerfd fail");
            abort();
        }
        return val;
    }

    //对事件轮进行增删查改的操作，需要保证线程安全，就要通过EventLoop来实现在一个线程中执行
    void release_timer(long unsigned int id)
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
        {
            _timers.erase(it);
        }else {
        ERR_LOG("Timer with id %lu not found", id);
        }
    }
    void add_timer(long unsigned int id, unsigned int timeout, const task_cb& cb)
    {
        std::shared_ptr<TimerTask> timer(new TimerTask(id, timeout, cb));//创建事件结构体
        timer->set_delTimer(std::bind(&TimeWheel::release_timer, this, id));//设置从时间轮删除事件的回调
        //将事件添加到时间轮
        unsigned int pos = (_tick + timeout) % _capacity;
        _wheel[pos].push_back(timer);
        //将事件添加到表中
        _timers[id] = (std::weak_ptr<TimerTask>) timer;
    }
    void flush_timer(long unsigned int id)
    {
        //在表中找timer
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            //没有这个事件，直接返回
            ERR_LOG("not found timer");
            return;
        }
        else
        {
            std::shared_ptr<TimerTask> timer = it->second.lock();//获取weak_ptr管理的对象对应的shared_ptr
            //将事件添加到时间轮
            unsigned int pos = (_tick + timer->get_timeout()) % _capacity;
            _wheel[pos].push_back(timer);
        }
    }

    void cancel_timer(long unsigned int id)
    {
         auto it = _timers.find(id);
        if (it == _timers.end()) {
            return;//没找着定时任务，没法刷新，没法延迟
        }
        std::shared_ptr<TimerTask> task = it->second.lock();
        if (task) task->Cancel();
    }

    void run_wheel()//时间轮转一次
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }
    //根据实时的超时次数，执行轮转操作
    void OnTime()
    {
        int time = ReadTimerfd();
        for(int i = 0; i < time; i++)
        {
            run_wheel();
        }
    }
public:
    TimeWheel(EventLoop* loop, int capacity = DEFAULT_TIMEWHEEL_SIZE)
    :_capacity(capacity),
    _tick(0),
    _wheel(_capacity)
    ,_timer_fd(InitTimerfd())
    ,_loop(loop)
    ,_channel(new Channel(_timer_fd, _loop))
    {
        //设置timerfd的读回调函数
        _channel->set_read_callback(std::bind(&TimeWheel::OnTime, this));
        //设置timerfd可读
        _channel->EnableRead();
    }

    //这些接口要使用EventLoop的函数，这里只写声明，在EventLoop定义后再实现
    void CancelTimerInLoop(long unsigned int id);
    void AddTimerInLoop(long unsigned int id, unsigned int timeout, const task_cb& cb);
    void FlushTimerInLoop(long unsigned int id);

    /*这个接口存在线程安全问题--这个接口实际上不能被外界使用者调用，只能在模块内，在对应的EventLoop线程内执行*/
    bool HasTimer(uint64_t id) 
    {
        auto it = _timers.find(id);
        if (it == _timers.end()) {
            return false;
        }
        return true;
    }
};

class EventLoop
{
private:
    int _event_fd;//用于唤醒事件监控可能造成的阻塞
    std::unique_ptr<Channel> _event_channel;//管理evenetfd
    std::thread::id _thread_id;//EventLoop的线程id
    using Func = std::function<void()>;
    std::vector<Func> _task_poll;//存储其它线程的任务到本线程的任务池
    std::mutex _mutex;//任务池的线程安全的锁
    Poller _poller;//事件监控

    TimeWheel _time_wheel;//时间轮定时器

    static int create_event_fd()
    {
        int ret = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if(ret < 0)
        {
            ERR_LOG("create eventfd fail");
            abort();//程序退出
        }
        return ret;
    }

    void eventfd_read()
    {
        uint64_t val = 0;
        int ret = read(_event_fd, &val, sizeof(val));
        if(ret < 0)
        {
            //EINTR表示被信号打断   EAGAIN表示无数据可读
            if(errno == EINTR || errno == EAGAIN)
            {
                return;
            }
            else
            {
                ERR_LOG("event read fail");
                abort();
            }
        }
    }

    void eventfd_wakeup()
    {
        uint64_t val = 1;
        int ret = write(_event_fd, &val, sizeof(val));
        if(ret < 0)
        {
            ERR_LOG("event wake fail");
            abort();
        }
    }

    //执行任务池中的任务
    void run_task_poll()
    {
        std::vector<Func> poll;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _task_poll.swap(poll);
            for(auto& e:poll)
            {
                e();
            }
        }
    }
public:
    EventLoop()
    :_event_fd(create_event_fd())
    ,_event_channel(new Channel(_event_fd, this))
    ,_thread_id(std::this_thread::get_id())
    ,_time_wheel(this)
    {
        //设置eventfd的读回调
        _event_channel->set_read_callback(std::bind(&EventLoop::eventfd_read, this));
        //设置eventfd可读
        _event_channel->Readable();
    }

    //完成EventLoop的任务,1.事件监控   2.就绪事件处理  3.完成任务池任务
    void Handle()
    {
        while(1)
        {
            //事件监控
            std::vector<Channel*> active;
            _poller.Handle(&active);

            //就绪事件处理
            for(auto& e:active)
            {
                e->HandleEvent();
            }

            //任务池任务执行
            run_task_poll();
        }
    }

    //判断任务是否在本线程
    bool IsInLoop()
    {
        return _thread_id == std::this_thread::get_id();
    }

    void AssertInLoop()
    {
        assert(_thread_id == std::this_thread::get_id());
    }
    //将任务压入任务池
    void PushInLoop(Func _cb)
    {
        //用锁保证线程安全
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _task_poll.push_back(_cb);
        }

        //唤醒可能因为没有事件就绪导致的Poller阻塞
        //如果一直阻塞，任务池中的任务一直不会被执行
        eventfd_wakeup();

    }
    //判断执行任务是否在本线程中，如果在就执行，如果不在就压入任务池中
    void RunInLoop(Func _cb)
    {
        //判断
        if(IsInLoop())
        {
            //执行
            _cb();
        }
        else
        {
            //压入任务池
            PushInLoop(_cb);
        }
    }

    void Update(Channel* channel)
    {
        _poller.Update(channel);
    }

    void Remove(Channel* channel)
    {
        _poller.Remove(channel);
    }

    //时间轮的接口
    void AddTimer(unsigned long id, unsigned int timeout, const task_cb &cb)
    {
        return _time_wheel.AddTimerInLoop(id, timeout, cb);
    }
    void CancelTimer(unsigned long id)
    {
        return _time_wheel.CancelTimerInLoop(id);
    }
    void FlushTimer(unsigned long id)
    {
        return _time_wheel.FlushTimerInLoop(id);
    }
    bool HasTimer(unsigned long id)
    {
        return _time_wheel.HasTimer(id);
    }
};

//移除所有监控
void Channel::RemoveAll()
{
    if (_loop) {
        _loop->Remove(this);
    } else {
        ERR_LOG("EventLoop is null in RemoveAll()");
    }
}

//更新监控事件
void Channel::UpdateAll()
{
    if (_loop) {
        _loop->Update(this);
    } else {
        ERR_LOG("EventLoop is null in UpdateAll()");
    }
}

void TimeWheel::CancelTimerInLoop(long unsigned int id)
{
    _loop->RunInLoop(std::bind(&TimeWheel::cancel_timer, this, id));
}

void TimeWheel::AddTimerInLoop(long unsigned int id, unsigned int timeout, const task_cb& cb)
{
   _loop->RunInLoop(std::bind(&TimeWheel::add_timer, this, id, timeout, cb));
}

void TimeWheel::FlushTimerInLoop(long unsigned int id)
{
   _loop->RunInLoop(std::bind(&TimeWheel::flush_timer, this, id));
}
